package com.wlk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wlk.mapper.GrantRecordMapper;
import com.wlk.mapper.ProjectMapper;
import com.wlk.mapper.ReimbMapper;
import com.wlk.pojo.Project;
import com.wlk.pojo.dto.AddProDTO;
import com.wlk.pojo.dto.CodeAnalysisDTO;
import com.wlk.pojo.dto.ProMoneyDTO;
import com.wlk.pojo.dto.ReimbSelProDTO;
import com.wlk.service.GrantRecordServcie;
import com.wlk.service.ProjectService;
import com.wlk.utils.CodeAnalysisUtil;
import com.wlk.utils.Result;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper,Project> implements ProjectService {
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ReimbMapper reimbMapper;
    @Resource
    private GrantRecordMapper grantRecordMapper;
    @Override
    @Transactional
    public Result addPro(AddProDTO addProDTO) {
        Project project = new Project();
        // 对数据进行解析和校验
        //将addProDTO中的数据取出
        String proName = addProDTO.getProName();
        String proCode = addProDTO.getProCode();
        String depCode = addProDTO.getDepCode();
        String depName = addProDTO.getDepName();
        BigDecimal amountMoneyA = addProDTO.getAmountMoneyA();
        BigDecimal amountMoneyB = addProDTO.getAmountMoneyB();
        BigDecimal amountMoneyC = addProDTO.getAmountMoneyC();
        BigDecimal effectiveAmountMoney;
        Integer headerId = addProDTO.getHeaderId();
        // 对addProDTO中的数据进行null或者""的校验，如果数据缺失，返回错误信息
        if (proName == null || proName.equals("")) {
            return Result.fail("项目名称不能为空");
        }
        if (proCode == null || proCode.equals("")) {
            return Result.fail("项目编码不能为空");
        }
        if (depCode == null || depCode.equals("")) {
            return Result.fail("部门编码不能为空");
        }
        if (depName == null || depName.equals("")) {
            return Result.fail("部门名称不能为空");
        }
        if (amountMoneyA == null) {
            return Result.fail("金额A不能为空");
        }
        if (amountMoneyB == null) {
            return Result.fail("金额B不能为空");
        }
        if (amountMoneyC == null) {
            return Result.fail("金额C不能为空");
        }
        if (headerId == null) {
            return Result.fail("项目负责人不能为空");
        }
        //计算有效金额
        effectiveAmountMoney = amountMoneyA.add(amountMoneyB).subtract(amountMoneyC);
        if (effectiveAmountMoney.compareTo(BigDecimal.ZERO) < 0){
            return Result.fail("有效金额不能为负数");
        }
        //对项目使用工具进行解析
        CodeAnalysisDTO proCodeAnalysisDTO = CodeAnalysisUtil.analyzeCode(proCode, 3);
        if (proCodeAnalysisDTO.equals(new CodeAnalysisDTO(-1,-1))) {
            //不符合编码规则
            return Result.fail("代码不符合编码规则，请检查后重新输入！");
        }
        //工具解析的数据
        String parentProCode = String.valueOf(proCodeAnalysisDTO.getParent());
        Integer level = proCodeAnalysisDTO.getLevel();
        //如果不是顶级项目，查看是否有父级项目
        Integer isParentExist = projectMapper.getProByProCode(parentProCode);
        if (level > 1 && isParentExist<0) {
            return Result.fail("不符合编码规则，不存在上一级部门");
        }
        // 查看传递的项目代码是否存在
        Integer isExist = projectMapper.getProByProCode(proCode);
        if (isExist > 0){
            return Result.fail("项目编码已存在");
        }
        //如果是顶级项目直接添加
        if (level == 1) {
            project.setProName(proName);
            project.setProCode(proCode);
            project.setDepCode(depCode);
            project.setDepName(depName);
            project.setProLevel(level);
            project.setAmountMoneyA(amountMoneyA);
            project.setAmountMoneyB(amountMoneyB);
            project.setAmountMoneyC(amountMoneyC);
            project.setEffectivAmountMoney(effectiveAmountMoney);
            project.setHeaderId(headerId);
            Integer i = projectMapper.addPro(project);
            if (i > 0) {
                return Result.ok("添加成功");
            }else {
                return Result.fail("添加失败");
            }
        }
        //如下操作针对添加非顶级项目
        if (level > 1) {
            // 非顶级项目，查看父级项目是否在报销单中使用
            Integer i = reimbMapper.isProInUse(parentProCode);
            if (i > 0) {
                return Result.fail("父级项目在报销单中使用，不能添加");
            }
        }
        // 查看是否为当前节点的第一个子节点，如果是，则继承该父节点的金额数据
        String proParentCode = parentProCode+"__";
        Integer count = projectMapper.isFirstSon(proParentCode);
        // count小于0，说明没有子节点，说明已经不存在子节点，继承父节点的金额数据
        if (count < 0) {
                // 继承父节点的金额数据
            Project projectParent = projectMapper.selectOne(new QueryWrapper<Project>().eq("pro_code", parentProCode));
            project.setProName(proName);
            project.setProCode(proCode);
            project.setDepCode(depCode);
            project.setDepName(depName);
            project.setProLevel(level);
            project.setAmountMoneyA(projectParent.getAmountMoneyA());
            project.setAmountMoneyB(projectParent.getAmountMoneyB());
            project.setAmountMoneyC(projectParent.getAmountMoneyC());
            project.setEffectivAmountMoney(projectParent.getEffectivAmountMoney());
            project.setHeaderId(headerId);
        } else {
            // 不是第一个子节点，则不继承父节点的金额数据
            project.setProName(proName);
            project.setProCode(proCode);
            project.setDepCode(depCode);
            project.setDepName(depName);
            project.setProLevel(level);
            project.setAmountMoneyA(amountMoneyA);
            project.setAmountMoneyB(amountMoneyB);
            project.setAmountMoneyC(amountMoneyC);
            project.setEffectivAmountMoney(effectiveAmountMoney);
            project.setHeaderId(headerId);
        }
        //添加项目
        Integer i = projectMapper.addPro(project);
        if (i > 0) {
            //更新所有父节点的金额数据（从子节点开始向上寻找父节点，直到找到顶级节点，然后更新父节点的金额数据）
            CodeAnalysisDTO codeAnalysisDTO = CodeAnalysisUtil.analyzeCode(proCode, 3);
            Integer level1 = codeAnalysisDTO.getLevel();
            String proParentCode1 = String.valueOf(codeAnalysisDTO.getParent());
            while(level1>1){
                ProMoneyDTO proMoneyDTO = projectMapper.getProMoneyList((proParentCode1+"__"));
                Integer proMoney = projectMapper.updateProMoney(proParentCode1, proMoneyDTO.getAmountMoneyA(), proMoneyDTO.getAmountMoneyB(), proMoneyDTO.getAmountMoneyC(), proMoneyDTO.getEffectivAmountMoney());
                projectMapper.updateProDetailed(proParentCode1);
                if(proMoney<0){
                    return Result.fail("更新失败");
                }
                 codeAnalysisDTO = CodeAnalysisUtil.analyzeCode(proParentCode1, 3);
                level1 = codeAnalysisDTO.getLevel();
                proParentCode1 = String.valueOf(codeAnalysisDTO.getParent());
            }


            return Result.ok("添加成功");
        } else {
            return Result.fail("添加失败");
        }
        //返回成功信息

    }
    /**
     * @description: 获取项目列表
     * @author:
     * @date: 2024/6/17 下午2:32
     * @param:
     * @return:
     **/
    @Override
    public Result getProList() {
        return Result.ok(projectMapper.getProList());
    }

    @Override
    public Result getGrantedProByUserId(Integer userId) {
        //从两个表进行查找，最后进行汇总，首先是项目表中查找，然后在授权记录表中进行连结查找
        List<ReimbSelProDTO> grantedProByUserId = projectMapper.getGrantedProByUserId(userId);
        List<ReimbSelProDTO> grantedProByUserIdLinkedGrant = projectMapper.getGrantedProByUserIdLinkedGrant(userId);
        //将两个列表去重合并返回
        // 合并两个结果集
        List<ReimbSelProDTO> combinedList = new ArrayList<>();
        combinedList.addAll(grantedProByUserId);
        combinedList.addAll(grantedProByUserIdLinkedGrant);

        // 去除重复项
        Set<ReimbSelProDTO> set = new HashSet<>(combinedList);
        List<ReimbSelProDTO> mergedAndDistinctList = new ArrayList<>(set);
        return Result.ok(mergedAndDistinctList);
    }

    @Override
    public Result getProListByHeaderId(Integer headerId) {
        return Result.ok(projectMapper.getProListByHeaderId(headerId));
    }



    @Override
    public Result delProByProCode(String proCode) {
        //对项目代码对应的项目进行删除资格校验
        String paramProCode = proCode+"__";
        Integer existSonPro = projectMapper.isExistSonPro(paramProCode);
        if(existSonPro>0){
            return Result.fail("存在子项目，不能删除");
        }

        Integer existReimbByProCode = reimbMapper.isExistReimbByProCode(proCode);
        if(existReimbByProCode>0){
            return Result.fail("报销单中存在该项目，不能删除");
        }

        /*
         * 有以下几点：
         *   1.报销单中存在的项目不能删除
         *   2.存在子项目的项目不能删除
         *
         * */
        // 经过校验后已经满足删除的条件，先存储必要的信息后进行删除更新
        Project targetProject = projectMapper.getProjectByProCode(proCode);
        //将四个金额进行存储
        BigDecimal amountMoneyA = targetProject.getAmountMoneyA();
        BigDecimal amountMoneyB = targetProject.getAmountMoneyB();
        BigDecimal amountMoneyC = targetProject.getAmountMoneyC();
        BigDecimal effectivAmountMoney = targetProject.getEffectivAmountMoney();


        /*
         * 满足删除条件后需要进行的操作
         * 1.删除项目后
         * 2.更新父节点的金额数据
         * 3.删除授权记录表中所有该存在该项目代码的授权记录
         *
         *
         * */
        //检查自己是否是顶级节点，如果是顶级节点，直接删除，不需要更新父节点的金额数据
        CodeAnalysisDTO codeAnalysisDTO1 = CodeAnalysisUtil.analyzeCode(proCode, 3);
        if(codeAnalysisDTO1.getParent().equals(-1)){
            projectMapper.delProByProCode(proCode);
            return Result.ok("删除成功");
        }
        String proParentCode = String.valueOf(codeAnalysisDTO1.getParent());
        String likeParentCode = proParentCode.trim()+"__";
        Integer proLevel = codeAnalysisDTO1.getLevel();
        Integer isExistSameLevelNodeByParentCode = projectMapper.checkSameLevelNodeByParentCode(likeParentCode, proLevel);
        // 如果不是顶级节点，如果是最后一个子节点，则需要更新父节点的状态为明细节点
        // 1.删除项目
        Integer i = projectMapper.delProByProCode(proCode);
        if (i > 0) {
            if(isExistSameLevelNodeByParentCode<=1){
                projectMapper.updateProDetailedSetOne(proParentCode);
            }
            CodeAnalysisDTO codeAnalysisDTO = CodeAnalysisUtil.analyzeCode(proCode, 3);
            Integer level1 = codeAnalysisDTO.getLevel();
            String proParentCode1 = String.valueOf(codeAnalysisDTO.getParent());
            while(level1>1){
                //获取 上一级，并获取上一级的4个金额数据，之前存储的金额更新进数据库
                Project project = projectMapper.getProjectByProCode(proParentCode1);
                //获取上级项目的四个金额
                BigDecimal amountMoneyA1 = project.getAmountMoneyA();
                BigDecimal amountMoneyB1 = project.getAmountMoneyB();
                BigDecimal amountMoneyC1 = project.getAmountMoneyC();
                BigDecimal effectivAmountMoney1 = project.getEffectivAmountMoney();
                //更新四个金额
                amountMoneyA1 = amountMoneyA1.subtract(amountMoneyA);
                amountMoneyB1 = amountMoneyB1.subtract(amountMoneyB);
                amountMoneyC1 = amountMoneyC1.subtract(amountMoneyC);
                effectivAmountMoney1 = effectivAmountMoney1.subtract(effectivAmountMoney);
                //更新父节点的金额
                Integer proMoney = projectMapper.updateProMoney(proParentCode1, amountMoneyA1, amountMoneyB1, amountMoneyC1, effectivAmountMoney1);
                if(proMoney<0){
                    return Result.fail("更新失败");
                }
                //继续解析
                codeAnalysisDTO = CodeAnalysisUtil.analyzeCode(proParentCode1, 3);
                level1 = codeAnalysisDTO.getLevel();
                proParentCode1 = String.valueOf(codeAnalysisDTO.getParent());
            }
            // 2.删除授权记录表中所有该存在该项目代码的授权记录
            Integer delGrant = grantRecordMapper.delGrantByProCode(proCode);
            return Result.ok("删除成功");

        }else {
            return Result.fail("删除失败");
        }

    }
}
